/**
 *******************************************************************************
 * @FileName  : custom_svc.c
 * @Author    : GaoQiu
 * @CreateDate: 2020-05-18
 * @Copyright : Copyright(C) GaoQiu
 *              All Rights Reserved.
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * GaoQiu and is available under the terms of Commercial License Agreement
 * between GaoQiu and the licensee in separate contract or the terms described
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */
#include "stack/host/att_uuid.h"
#include "stack/host/dm_api.h"
#include "utils/byte_stream.h"
#include "svc_handle.h"
//#include "bsp/bsp.h"

AttState_t GW_WriteCback(uint16_t connHandle, uint16_t attHandle, uint8_t opcode, uint16_t offset,
		                 uint8_t *pValue, uint32_t len, AttsAttr_t* pAttr);

/*! GuoWang Server ------------------------------------------------------------*/
/*! Service UUID */             //LSB
static const uint8_t meterServiceUUID[16] = {0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E};
static const uint16_t meterSvcLen = sizeof(meterServiceUUID);

/*! Characteristic  Declare */
//1. Received data Characteristic UUID(Write without response)
static const uint8_t meterRxCharUUID[16] = {0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E};

static const char_prop_t meterRxProp = {
	.prop          = ATT_PROP_WRITE_NO_RSP,
	.attHandle     = GW_RX_VALUE_HDL,
	.UUID.UUID_128 = {0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E},
};//use for Characteristic declaration
//static const uint8_t meterRxProp[] = {ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(GW_RX_VALUE_HDL), 0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E};
static const uint16_t meterRxPropLen = sizeof(meterRxProp);

/*! Rx Value */
static uint8_t rxValue[250] = {0};
static uint16_t rxValLen = sizeof(rxValue);

static uint8_t rxUserDes[] ="Rx Data";
static uint16_t rxUserDesLen = sizeof(rxUserDes);

/*! 2. Transmit data Characteristic UUID(Notification) */
static const uint8_t meterTxCharUUID[] = {0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E};
static const char_prop_t meterTxProp = {
	.prop          = ATT_PROP_NOTIFY|ATT_PROP_READ,//If set, the Client Characteristic Configuration Descriptor(CCCD) shall exist.
	.attHandle     = GW_TX_VALUE_HDL,
	.UUID.UUID_128 = {0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E,},
};
//static const uint8_t meterTxProp[] = {ATT_PROP_NOTIFY|ATT_PROP_READ, UINT16_TO_BYTES(GW_TX_VALUE_HDL), 0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E};
static const uint16_t meterTxPropLen = sizeof(meterTxProp);


/*! Tx Value */
static uint8_t txValue[20] = {0};
static uint16_t txValLen = sizeof(txValue);

static uint8_t clientCharValue[] = {UINT16_TO_BYTES(0x0001)};//default CCCD value = 0x0000; 0x0001->notify
static uint16_t clientCharValueLen = sizeof(clientCharValue);

static uint8_t txUserDes[] ="Tx Data";
static uint16_t txUserDesLen = sizeof(txUserDes);

static const AttsAttr_t gwAttrs[] = {
	{
		primSvcUuid,
		(uint8_t*)meterServiceUUID,
		(uint16_t*)&meterSvcLen,
		sizeof(meterServiceUUID),
		0,
		ATTS_PERMIT_READ,
	},
	//Rx
	{
		charDecUuid,
		(uint8_t*)&meterRxProp,
		(uint16_t*)&meterRxPropLen,
		sizeof(meterRxProp),
		0,
		ATTS_PERMIT_READ,
	},
	{//value
		meterRxCharUUID,
		rxValue,
		&rxValLen,
		sizeof(rxValue),//500,//sizeof(rxValue),
		ATTS_SET_UUID_128|ATTS_SET_WRITE_CBACK|ATTS_SET_VARIABLE_LEN,
		ATTS_PERMIT_READ|ATTS_PERMIT_WRITE,
	},
	{
		userDescUuid,
		rxUserDes,
		&rxUserDesLen,
		sizeof(rxUserDes),
		0,
		ATTS_PERMIT_READ|ATTS_PERMIT_WRITE,
	},
	//TX
	{
		charDecUuid,
		(uint8_t *)&meterTxProp,
		(uint16_t*)&meterTxPropLen,
		sizeof(meterTxProp),
		0,
		ATTS_PERMIT_READ,
	},
	{//value
		meterTxCharUUID,
		txValue,
		&txValLen,
		sizeof(txValue),
		ATTS_SET_UUID_128,
		ATTS_PERMIT_READ,
	},
	{//CCCD
		clientCharCfgUuid,
		clientCharValue,
		&clientCharValueLen,
		sizeof(clientCharValue),
		ATTS_SET_CCC,
		ATTS_PERMIT_READ|ATTS_PERMIT_WRITE,
	},
	{
		userDescUuid,
		txUserDes,
		&txUserDesLen,
		sizeof(txUserDes),
		0,
		ATTS_PERMIT_READ,
	},
};


AttsGroup_t gwGrp = {
	NULL,
	(AttsAttr_t *)&gwAttrs[0],
	NULL,
	GW_WriteCback,
	GW_SVC_START_HDL,
	GW_SVC_END_HDL,
};

uint8_t GW_SendData(uint16_t connHandle, uint8_t *pData, uint32_t len)
{
#if 1
	if(ATTS_CccEnabled(connHandle, GW_TX_CCC_IDX)){
		uint8_t res = ATTS_ValueNotify(connHandle, GW_TX_VALUE_HDL, pData, len);
		return res;
	}
#else //[Panchip]
	return ATTS_ValueNotify(connHandle, GW_TX_VALUE_HDL, pData, len);
#endif
	//ATT_TRACK_ERR("NOTIFY is not enabled\r\n");
	return BLE_ERR_ATT_SERVER_NOTIFY_NOT_ENABLED;
}

uint32_t A_rx_pkt_cnt = 0;
uint32_t A_tx_pkt_cnt = 0;

__WEAK void GW_RxDataHandler(uint16_t connHandle, uint8_t *pdata, uint32_t len)
{
#if 0
	uint8_t *p = pdata;
	uint32_t rxCnt = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
	if(A_rx_pkt_cnt != rxCnt){
		APP_TRACK_INFO("RX Data error(len:%d, rxCnt:%d) \r\n", len, A_rx_pkt_cnt);
		APP_TRACK_DATA(p, len);
		return;
	}

	uint8_t token = 0x77;
	for(int i=4; i<len; i++)
	{
		if(p[i] != token){
			APP_TRACK_INFO("RX Data error(len:%d, rxCnt:%d) \r\n", len, A_rx_pkt_cnt);
			APP_TRACK_DATA(p, len);
			return;
		}
	}
#else
	APP_TRACK_INFO("RX Data(len:%d, rxCnt:%d) \r\n", len, A_rx_pkt_cnt);
	APP_TRACK_DATA(pdata, min(20, len));
#endif

	A_rx_pkt_cnt++;
}

AttState_t GW_WriteCback(uint16_t connHandle, uint16_t attHandle, uint8_t opcode, uint16_t offset,
		                 uint8_t *pValue, uint32_t len, AttsAttr_t* pAttr)
{
	bool_t needAck = false;
	UNUSED(needAck);

	switch(opcode)
	{
	case ATT_WRITE_CMD:
	{
		if(attHandle == GW_RX_VALUE_HDL)
		{
			GW_RxDataHandler(connHandle, pValue, len);
		}
		break;
	}
	default:
		break;
	}
	return ATT_SUCCESS;
}
